package com.killer.servlet;

import com.alibaba.fastjson.JSONObject;
import com.killer.anno.Controller;
import com.killer.anno.RequestMapping;
import com.killer.context.XmlWebApplicationContext;
import com.killer.factory.DefaultListableBeanFactory;
import com.killer.handler.HandlerExecutionChain;
import com.killer.handler.HandlerInterceptor;
import com.killer.handler.InterceptorDefinition;
import com.killer.handler.MethodHandler;
import com.killer.pojo.BeanDefinition;

import javax.servlet.ServletConfig;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.lang.reflect.Method;
import java.lang.reflect.Parameter;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;

/**
 * @author ：Killer
 * @date ：Created in 20-10-26 下午4:22
 * @description：${description}
 * @modified By：
 * @version: version
 */
public class DispatcherServlet extends HttpServlet {

    private XmlWebApplicationContext xmlWebApplicationContext;

    /**
     * 处理器映射器列表
     */
    private List<MethodHandler> handlerMappings = new ArrayList<MethodHandler>();

    @Override
    public void init(ServletConfig config) throws ServletException {
        String location=config.getInitParameter("contextConfigLocation");
        try {
            //这里是初始化springmvc容器，里面只有controller层以及在springmvc配置文件中定义的对象,service以及dao层的对象将会定义到它的富容器中
            xmlWebApplicationContext = new XmlWebApplicationContext(location);
            //初始化springmvc组件 这里也是为了简便，就不用spring的那种事件发布机制，这里也不做jsp展示，只返回json
            initStrategies();
        } catch (Exception e) {
            throw new RuntimeException("加载springmvc容器失败");
        }
    }

    protected void initStrategies() throws Exception {
        //这里只初始化handlerMapping,简化版
        initHandlerMappings();
    }

    private void initHandlerMappings() throws Exception {
        //获取对象工厂
        DefaultListableBeanFactory beanFactory = xmlWebApplicationContext.getBeanFactory();
        //获取所有注册了的bean
        Map<String, BeanDefinition> registerFactory = beanFactory.getRegisterFactory();
        //遍历所有bean
        for (Map.Entry<String, BeanDefinition> entry : registerFactory.entrySet()) {
            //获取beanDefition
            BeanDefinition beanDefinition=entry.getValue();
            //获取class类型
            Class<?> beanClass = beanDefinition.getBeanClass();
            //获取该对象
            Object object = xmlWebApplicationContext.getBean(entry.getKey());
            //查看是否有controller注解
            Controller controller = beanClass.getAnnotation(Controller.class);
            if (controller == null) {
                //没有controller注解则跳过
                continue;
            }
            //查看类上是否有requestMapping注解
            RequestMapping parentRequestMapping = beanClass.getAnnotation(RequestMapping.class);
            String prefix=parentRequestMapping==null?"":parentRequestMapping.value();
            //遍历所有方法
            Method[] declaredMethods = beanClass.getDeclaredMethods();
            if (declaredMethods != null) {
                for(Method declaredMethod:declaredMethods){
                    //查看方法上是否有RequestMapping注解
                    RequestMapping requestMapping = declaredMethod.getAnnotation(RequestMapping.class);
                    //没有该注解，该方法就不需要注册成handler
                    if (requestMapping == null) {
                        continue;
                    }
                    String url=requestMapping.value();
                    MethodHandler methodHandler=new MethodHandler();
                    methodHandler.setHandler(object);
                    methodHandler.setMethod(declaredMethod);
                    methodHandler.setPath(prefix+url);
                    handlerMappings.add(methodHandler);
                }
            }

        }
    }

    private void doDispatcher(HttpServletRequest req, HttpServletResponse resp) throws Exception{
        //获取请求路径
        String requestPath = req.getRequestURI();
        HandlerExecutionChain handlerExecutionChain = getHandlerExecutionChain(requestPath);
        //先执行过滤器
        boolean flag=true;
        for (HandlerInterceptor interceptor : handlerExecutionChain.getHandlerInterceptorList()) {
            flag = interceptor.preHandle(req, resp, handlerExecutionChain.getMethodHandler());
        }
        //只要拦截器有一个不通过，就直接不通过
        if (!flag) {
            return;
        }
        //获取执行的方法
        MethodHandler methodHandler = handlerExecutionChain.getMethodHandler();
        Method method=methodHandler.getMethod();
        Object handler=methodHandler.getHandler();
        //获取方法参数
        Parameter[] parameters = method.getParameters();
        Object[] args = parameters == null ? null : new Object[parameters.length];
        if (parameters != null) {
            for (int i=0;i<parameters.length;i++) {
                Parameter parameter = parameters[i];
                //获取参数名字 但是这里要注意必须编译的时候将参数名字生成,要不然只能够通过requestParam注解手动绑定
                String name = parameter.getName();
                //获取对应的请求参数  这里也是简化版，先做字符串的
                String value = req.getParameter(name);
                args[i]=value;
            }
        }

        Object result=method.invoke(handler,args);
        resp.setCharacterEncoding("utf-8");
        //这里默认json形式返回前端
        resp.getWriter().write(JSONObject.toJSONString(result));
    }

    private HandlerExecutionChain getHandlerExecutionChain(String requestPath) throws Exception {
        HandlerExecutionChain handlerExecutionChain=new HandlerExecutionChain();
        for (MethodHandler handler : handlerMappings) {
            if (handler.getPath().equals(requestPath)) {
                handlerExecutionChain.setMethodHandler(handler);
                break;
            }
        }
        List<HandlerInterceptor> handlerInterceptors = new ArrayList<HandlerInterceptor>();
        //查找匹配的过滤器
        List<InterceptorDefinition> interceptorDefinitions=xmlWebApplicationContext.getInterceptors();
        for (InterceptorDefinition interceptorDefinition : interceptorDefinitions) {
            //这里也是简化版，只做精确匹配
            if (interceptorDefinition.getPaths().contains(requestPath)) {
                HandlerInterceptor handlerInterceptor = (HandlerInterceptor) xmlWebApplicationContext.getBean(interceptorDefinition.getName());
                handlerInterceptors.add(handlerInterceptor);
            }
        }
        handlerExecutionChain.setHandlerInterceptorList(handlerInterceptors);
        return handlerExecutionChain;
    }

    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        try {
            doDispatcher(req, resp);
        } catch (Exception e) {
            throw new RuntimeException("处理请求失败");
        }
    }


    protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        doGet(req, resp);
    }
}
